プログラマーだけん、がんばる

神の国、島根のプログラマー。サーバ、Rubyまわりの技術(Ruby on Rails, Rhodes etc..)やiOS, Androidなどの開発を行っていくうえで、役だったことなどを共有できればいいなと思います。

Objective-Cのカテゴリによる既存クラスの拡張とRubyのオープンクラスによる既存クラスの拡張

こんにちは。今回は題名通り、Objective-Cのカテゴリによる既存クラスの拡張とRubyのオープンクラスによる既存クラスの拡張のやり方を紹介します。

今回はObjective-CのNSStringクラスへ@"sample string"を返す、sampleというクラスメソッドと、
RubyのStringクラスへ'sample string'を返す、sampleというクラスメソッドを作成します。

まずObjective-cによる既存クラスの拡張です。

Objective-Cによる既存クラスの拡張

Objective-Cによる既存クラスの拡張を行うにはカテゴリという機能を使用します。
カテゴリとは、クラスの持つメソッドをカテゴリごとに分類するメソッドです。
この機能を使用することによって、メソッドが沢山ある大きなクラスを分かりやすく分類することが出来ます。
カテゴリの名前は自由につけることが出来ますが、用途によって分かりやすい名前がいいと思います。
今回は「Sample」というカテゴリ名にします。

まずiPhoneアプリの新しいプロジェクトを作成します。
Xcodeを起動して、「Create a new Xcode project」をクリックして作成します。
テンプレートは「empty project」でプロジェクト名は「SampleCategory」にします。
f:id:famtom:20131012193703j:plain

次に、フォルダツリーの上で、右クリックして、「New File」-> 「Objective-C class」を選択します。
その次に下記の画面で、classに「Sample」、subclass ofに「NSString」を選択します。
後で修正するので、実際のところなんでもいいです。
f:id:famtom:20131012194326p:plain
ファイルを作成したら 、
「Sample.h」を「NSString+Sample.h」に、
「Sample.m」を「NSString+Sample.m」にリネームします。
ファイルの名前はなんでもいいのですが慣習的に、「拡張するクラス名+カテゴリ名」とするのが一般的のようです。

この2つのファイルにカテゴリ拡張のコードを記述します。

まず、NSString+Sample.hを下記のようにします。

・NSString+Sample.h

#import <Foundation/Foundation.h>

@interface NSString (Sample) //拡張するクラス名(カテゴリ名)
+(NSString*) sample; //作成するクラスメソッドの宣言
@end

ヘッダファイルの実装はこれで終わりです。

次に、NSString+Sample.mを下記のように実装します。


・NSString+Sample.m

#import "NSString+Sample.h"

@implementation NSString (Sample)
+(NSString*)sample{
  return @"sample string";
}

@end

これで実装は終了です。

最後に結果を確認するにAppDelegate.mにメソッドの返り値をアラート表示するプログラムをつけたします。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    // ここからアラート表示プログラムの追加
    UIAlertView *alert =[[UIAlertView alloc]
                         initWithTitle: @"タイトル"
                         message: [NSString sample] // 拡張したメソッドを実行
                         delegate:nil
                         cancelButtonTitle:nil
                         otherButtonTitles:@"OK", nil
                         ];
    [alert show];
    //ここまで

    return YES;
}

まぁ、結果が確認できればOKなので、NSLogでもいいんですけどね。
実行結果が下記のようになります。

f:id:famtom:20131012195927p:plain

結果が確認出来ました。
注意点とては、クラスのインスタンス変数は追加できません。
以上が、Objective-Cのカテゴリによる既存クラスの拡張です。
非常に強力で、魅力的な機能です。

Rubyのオープンクラスによる既存クラスの拡張

Rubyのオープンクラスによる既存クラスの拡張は、Objective-Cのカテゴリによる既存クラスの拡張に比べ、
非常に簡単に実装できます。(個人的に)

まずstring.rbというファイルを作成し、下記の実装をします。
今回は、メソッドの定義と同じファイルに結果を出力するコードを書きます。

class String
  def self.sample
    'sample string'
  end
end

puts String.sample

実装はこれで終わります。
これで、既存のStringというクラスにsampleというクラスメソッドが追加できました。
最後に実行して、

$ ruby string.rb
#=> sample string

という結果になればOKです。

最後に

以上がObjective-CRubyによる、既存クラス拡張例です。
非常に強力ですが、使い所や、間違った使い方をしてしまうと、解決しにくいバグを作ってしまう可能性があるので注意して下さい。
とはいえ、開発をしていればこういったことをしたいと思う時が必ずくると思うので、
頭の隅にでも記憶しておいてもらえれば幸いです。

今回の作成したサンプルのソースです。GitHubで確認できます。

  • Objective-Cのカテゴリによる既存クラスの拡張

https://github.com/tomomura/objective-c-sample-category

  • Rubyのオープンクラスによる既存クラスの拡張

https://github.com/tomomura/ruby-open-class-sample