3

次のようなカテゴリを使用UIButtonTypeして、クラスに新しいカスタムを追加したいと思います。UIButton

enum {
    UIButtonTypeMatteWhiteBordered = 0x100
};

@interface UIButton (Custom)

+ (id)buttonWithType:(UIButtonType)buttonType;

@end

superどういうわけか、そのオーバーライドされたメソッドの実装を取得することは可能ですか?

+ (id)buttonWithType:(UIButtonType)buttonType {
    return [super buttonWithType:buttonType];
}

上記のコードは、このコンテキストでsuper参照しているため、無効です。UIControl

4

3 に答える 3

7

次のように、実行時にメソッドを独自のカスタム メソッドに置き換えることができます。

#import <objc/runtime.h>

@implementation UIButton(Custom)

// At runtime this method will be called as buttonWithType:
+ (id)customButtonWithType:(UIButtonType)buttonType 
{
    // ---Add in custom code here---

    // This line at runtime does not go into an infinite loop
    // because it will call the real method instead of ours. 
    return [self customButtonWithType:buttonType];
}

// Swaps our custom implementation with the default one
// +load is called when a class is loaded into the system
+ (void) load
{
    SEL origSel = @selector(buttonWithType:);

    SEL newSel = @selector(customButtonWithType:);

    Class buttonClass = [UIButton class];

    Method origMethod = class_getInstanceMethod(buttonClass, origSel);
    Method newMethod = class_getInstanceMethod(buttonClass, newSel);
    method_exchangeImplementations(origMethod, newMethod);
}

これをどのように使用するかに注意してください。アプリが使用するすべての UIButton のデフォルトの実装が置き換えられることに注意してください。また、+load をオーバーライドするため、既に +load メソッドを持ち、それに依存しているクラスでは機能しない可能性があります。

あなたの場合、UIButton をサブクラス化した方が良いかもしれません。

編集:Tylerが以下に記しているように、クラスレベルのメソッドを使用してボタンを作成する必要があるため、これが作成をオーバーライドする唯一の方法である可能性があります。

于 2010-12-03T18:46:51.037 に答える
3

いいえ、カテゴリを使用してクラスの機能を拡張する場合、これは不可能です。クラスを拡張するのではなく実際には既存のメソッドを完全にオーバーライドし、元のメソッドを完全に失います。風のように去った。

のサブクラスを作成するとUIButton、これが完全に可能になります。

enum {
    UIButtonTypeMatteWhiteBordered = 0x100
};

@interface MyCustomButton : UIButton {}

@end

@implementation MyCustomButton 

+ (id)buttonWithType:(UIButtonType)buttonType {
    return [super buttonWithType:buttonType]; //super here refers to UIButton
}

@end
于 2010-12-03T16:40:39.463 に答える
3

ジェイコブは、カテゴリ メソッドがサブクラス メソッドとは異なる動作をすることを強調しています。Apple は、完全に新しいカテゴリ メソッドのみを提供することを強くお勧めします。これは、そうしないとうまくいかないことが複数あるためです。その 1 つは、カテゴリ メソッドを定義すると、同じ名前のメソッドの他の既存の実装が基本的にすべて消去されることです。

残念ながら、あなたがやろうとしていることは、UIButtonサブクラス化を避けるように特別に設計されているようです。a のインスタンスを取得する唯一の認可された方法UIButtonは、コンストラクターを使用すること[UIButton buttonWithType:]です。Jacobのようなサブクラスの問題は(このように)示唆しています:

@implementation MyCustomButton 

+ (id)buttonWithType:(UIButtonType)buttonType {
  return [super buttonWithType:buttonType]; //super here refers to UIButton
}

@end

によって返される型はではなく[MyCustomButton buttonWithType:]のままであるということです。Apple はinit メソッドを提供していないため、サブクラスがそれ自体をインスタンス化し、.UIButton MyCustomButtonUIButtonUIButton

カスタマイズされた動作が必要な場合UIViewは、ボタンを常にサブビューとして含むカスタム サブクラスを作成して、 の機能の一部を活用できUIButtonます。

このようなもの:

@interface MyButton : UIView {}

- (void)buttonTapped;

@end

@implementation MyButton

-(id)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = self.bounds;
    [button addTarget:self action:@selector(buttonTapped)
     forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:button];
  }
  return self;
}

- (void)buttonTapped {
  // Respond to a button tap.
}

@end

より複雑なユーザー インタラクションに応じてボタンにさまざまな動作をさせたい場合は、[UIButton addTarget:action:forControlEvents:]さまざまなコントロール イベントに対して をさらに呼び出すことができます。

参考:AppleのUIButtonクラスリファレンス

于 2010-12-03T21:05:33.550 に答える