Objective-Cクラスを継承したSwiftクラスで、継承元のメンバ変数を扱う方法

# はじめに
古くから存在するアプリでは、Objective-CとSwiftが共存していることがよくあります。はじめはObjective-Cで作られ、Swiftが発表された後はSwiftで作っている、というパターンですね。こういったアプリでは、Objective-Cで書かれたクラスをSwiftで継承する、という実装を行う場面が出てくると思います。そのときのメンバ変数の取り扱いで少し手間取ったので、備忘録として残します。

# サンプルファイル
以下に、この記事で扱うファイルを記載します。

## 継承元のObjective-Cファイル
継承元のクラスが書かれたファイルは以下であるとします。

```objective_c:SampleParentViewController.h
 
#import <UIKit/UIKit.h>

@protocol SampleDelegate

- (void) delegateMethod;

@end

@interface SampleParentViewController: UIViewController {
    id<SampleDelegate> sampleDelegate;
}

- (instancetype)initWithDelegate:(id<SampleDelegate>)delegate;

@end
```

```objective_c:SampleParentViewController.m
 
#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で書いたとします。

```swift:SampleChildViewController.swift
import UIKit

class SampleChildViewController: SampleParentViewController {
    
    let otherViewController: SampleDelegate = OtherViewController()

    override func viewDidLoad() {
        self.sampleDelegate = otherViewController
        super.viewDidLoad()
    }
}

```

しかし、このSwiftファイルをつくるとコンパイルエラーになります。以下で、このファイルの実装するための変更手順を示していきます。

# 変更手順
段階を追って、意図通りに動くための手順を示していきます。

## プロパティを追加
まずこのsampleDelegateはメンバ変数として定義されているため、クラスの外から参照することはできません。参照できるようにするには、メンバ変数ではなくプロパティに変更する必要があります。そのために、まずはヘッダファイルにプロパティの宣言を追加します。

```objective_c:SampleParentViewController.h
 
#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に書き換えていきます。

```objective_c:SampleParentViewController.m
 
#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の宣言を消しておきましょう。

```objective_c:SampleParentViewController.h
 
#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はハマると解決に時間がかかる仕様が多いと思います。そんな人の助けになれると幸いです。