Help us understand the problem. What is going on with this article?

単純に呼べば使えるAOPライブラリMOAspectsを作った

More than 3 years have passed since last update.

単純に呼べば使えるAOPライブラリMOAspectsを作った

Objective-CでAOPを実現するライブラリMOAspectsを一昨日ぐらいにCocoapodsに登録してきた。

MO-AI/MOAspects
https://github.com/MO-AI/MOAspects

AOPとは?

アスペクト指向(Aspect Oriented Programming)の略、難しい言葉だと横断的関心事の分離と言われている。要はロギングのような全体に散らばる処理を一括で管理できるようにしたことをアスペクトという。

なぜ作ったか?

あるときGoogleAnalyticsの埋め込みをやることになり画面毎、アクション毎にGoogleAnalytics用の定義を切る必要があったが、1つ1つの該当クラスにそのような対応を行うのが煩わしいため一括でその定義を切れるクラスが欲しくて作った。

他のAOPライブラリは?

steipete/Aspects
https://github.com/steipete/Aspects

tokorom/BlockInjection
https://github.com/tokorom/BlockInjection

有名なのだと上のようなライブラリがあるが、技術的課題点がいくつかあった。

Aspects

  • クラスメソッドに対して処理をフックできない
  • 同一クラス系統に対して複数処理をフックできない
    • UIViewController/UITableViewControllerなど

BlockInjection

  • 64bit対応でない
  • 同一クラス系統に対して複数処理をフックできない

このライブラリの売り所

  • 32bit/64bit対応
  • インスタンスメソッド/クラスメソッド対応
  • 同一クラス系統のクラスに対して複数フックが可能

表にするとこんな感じ

ライブラリ名 64bit対応 インスタンス
メソッド
クラス
メソッド
同一系統
クラスフック
Aspects × ×
BlockInjection × ×
MOAspects

とにかく実装上の都合を開発者に対して気を使わせないようなライブラリを目的とした。インターフェースとしてインスタンスメソッド・クラスメソッドのフック処理の2種類のみ用意しており、引数のClassとSELを基にターゲットを決定する。

インストール

pod 'MOAspects'

インターフェース

MOAspects.h
// hook instance method 
+ (BOOL)hookInstanceMethodForClass:(Class)clazz
                          selector:(SEL)selector
                   aspectsPosition:(MOAspectsPosition)aspectsPosition
                        usingBlock:(id)block;

// hook class method
+ (BOOL)hookClassMethodForClass:(Class)clazz
                       selector:(SEL)selector
                aspectsPosition:(MOAspectsPosition)aspectsPosition
                     usingBlock:(id)block;

MOAspectsPosition

MOAspectsPositionBeforeMOAspectsPositionAfterがあり、対象処理の前か後にフックを行うか選択することができる

block

この中にフックする処理を実装する。blockの型の記載がないが以下のようになる

void (^block) (id targetObject, Type1 parameter1, Type2 parameter2...)

使い方

クラスメソッドのフック例

[MOAspects hookClassMethodForClass:[NSNumber class]
                          selector:@selector(numberWithInt:)
                   aspectsPosition:MOAspectsPositionBefore
                        usingBlock:^(id class, int intVar){
                            NSLog(@"hooked %d number!", intVar);
                        }];

[NSNumber numberWithInt:10]; // -> hooked 10 number!

インスタンスメソッドのフック例

[MOAspects hookInstanceMethodForClass:[NSString class]
                             selector:@selector(length)
                      aspectsPosition:MOAspectsPositionBefore
                           usingBlock:^(NSString *string){
                               NSLog(@"hooked %@!", string);
                           }];

[@"abcde" length]; // -> hooked abcde!

Objective-Cな理由

Swiftでやろうと思ったが、このライブラリは内部でNSInvocationを使っているため現在SwiftだとNSInvocation is unavailableと怒られるため止む無くObjective-Cとなった

TODO

  • ドキュメント
  • ベンチマーク
  • 実際にGAと絡めたデモアプリ

最後に

実際に使ってみて元のコードを汚すことなくGoogleAnalyticsを埋め込めたので是非同じような状況になったら使ってみてはいかがでしょうか。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away