web-dev-qa-db-ja.com

カテゴリインターフェイス/実装で新しいプロパティを設定する

わかりました、これはありますが、機能しません:

@interface UILabel (touches)

@property (nonatomic) BOOL isMethodStep;

@end


@implementation UILabel (touches)

-(BOOL)isMethodStep {
    return self.isMethodStep;
}

-(void)setIsMethodStep:(BOOL)boolean {
    self.isMethodStep = boolean;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if(self.isMethodStep){
        // set all labels to normal font:
        UIFont *toSet = (self.font == [UIFont fontWithName:@"Helvetica" size:16]) ? [UIFont fontWithName:@"Helvetica-Bold" size:16] : [UIFont fontWithName:@"Helvetica" size:16];

        id superView = self.superview;
        for(id theView in [(UIView *)superView subviews])
            if([theView isKindOfClass:[UILabel class]])
                [(UILabel *)theView setFont:[UIFont fontWithName:@"Helvetica" size:16]];

        self.font = toSet;
    }
}

@end

Getterメソッドとsetterメソッドを削除すると、機能しなくなり、いくつかのgetterメソッドとsetterメソッドを作成する必要があることがわかります(または@synthesizeを使用しますが、@ implementationに@synthesizeを入れるとエラーもスローされます)。しかし、getterメソッドとsetterメソッドを使用すると、EXC_BAD_ACCESSとクラッシュが発生します。何か案は?ありがとう

トム

14
Thomas Clayson

カテゴリを介して既存のクラスにメンバーとプロパティを追加することはできません。メソッドのみです。

https://developer.Apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Category.html

考えられる回避策の1つは、シングルトンを使用して変数を保存する「セッター/ゲッターのような」メソッドを作成することです。これは、メンバーでした。

-(void)setMember:(MyObject *)someObject
{
    NSMutableDictionary *dict = [MySingleton sharedRegistry];
    [dict setObject:someObject forKey:self];
}

-(MyObject *)member
{
    NSMutableDictionary *dict = [MySingleton sharedRegistry];
    return [dict objectforKey:self];
}

または—もちろん—UILabelから継承するカスタムクラスを作成します


最近では、関連オブジェクトを実行時に挿入できることに注意してください。 Objective Cプログラミング言語:連想参照

39
vikingosegundo

すべての回答を確認しましたが、最も一般的な解決策は見つかりませんでした。

#import <objc/runtime.h>

static void const *key;

@interface ClassName (CategoryName)
@property (nonatomic) BOOL myProperty;
@end

@implementation ClassName (CategoryName)
- (BOOL)myProperty {
    return [objc_getAssociatedObject(self, key) boolValue];
}

- (void)setMyProperty:(BOOL)value {
    objc_setAssociatedObject(self, key, @(value), OBJC_ASSOCIATION_RETAIN);
}
@end

迅速:

private struct AssociatedKeys {
    static var keyName = "keyName"
}

extension Foo {
    var bar: Any! {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.keyName)
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.keyName , newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}
4
Kirow

実行時に関連するオブジェクトを挿入できます。

#import <objc/runtime.h>

@interface UIView (Private)

@property (nonatomic, assign) CGPoint initialTouchPoint;
@property (nonatomic, strong) UIWindow *alertWindow;

@end

@implementation UIView (Private)

@dynamic initialTouchPoint, alertWindow;

- (CGPoint)initialTouchPoint {
    return CGPointFromString(objc_getAssociatedObject(self, @selector(initialTouchPoint)));
}

- (void)setInitialTouchPoint:(CGPoint)initialTouchPoint {
    objc_setAssociatedObject(self, @selector(initialTouchPoint), NSStringFromCGPoint(initialTouchPoint), OBJC_ASSOCIATION_RETAIN);
}

- (void)setAlertWindow:(UIWindow *)alertWindow {
    objc_setAssociatedObject(self, @selector(alertWindow), alertWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIWindow *)alertWindow {
    return objc_getAssociatedObject(self, @selector(alertWindow));
}

@end
1
Lal Krishna

実際には、理想的ではないかもしれませんが、機能する方法があります。
これを機能させるには、クラスXのカテゴリを作成する必要があり、同じXのサブクラスでのみ使用できます(例:category UIView (Background) canクラスMyView : UIViewで使用できますが、UIViewで直接使用することはできません)

// UIView+Background.h

@interface UIView (Background)

@property (strong, nonatomic) NSString *hexColor;

- (void)someMethodThatUsesHexColor;

@end

// UIView+Background.h

@implementation UIView (Background)

@dynamic hexColor; // Must be declared as dynamic

- (void)someMethodThatUsesHexColor {
    NSLog(@"Color %@", self.hexColor);
}

@end

次に

// MyView.m

#import "UIView+Background.h"

@interface MyView : UIView

@property (strong, nonatomic) NSString *hexColor;

@end

@implementation MyView ()

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setHexColor:@"#BABACA"];
    [self someMethodThatUsesHexColor];
}

@end

このメソッドを使用すると、プロパティを「再宣言」する必要がありますが、その後、カテゴリ内ですべての操作を行うことができます。

1
Guilherme

Xcode 7(7.0.1、7A1001)以降、プロパティはカテゴリでサポートされているようです。 XcodeCore Dataサブクラスのカテゴリを生成することに気づきました。

たとえば、次のファイルを取得しました。

Location + CoreDataProperties.h

#import "Location.h"

NS_ASSUME_NONNULL_BEGIN

@interface Location (CoreDataProperties)

@property (nullable, nonatomic, retain) NSNumber *altitude;
@property (nullable, nonatomic, retain) NSNumber *latitude;
@property (nullable, nonatomic, retain) NSNumber *longitude;

@end

NS_ASSUME_NONNULL_END

Location + CoreDataProperties.m

#import "Location+CoreDataProperties.h"

@implementation Location (CoreDataProperties)

@dynamic altitude;
@dynamic latitude;
@dynamic longitude;

@end

したがって、カテゴリ内のプロパティが機能するようになりました。非Core Dataクラスではテストしていません。

私が気付いたのは、カテゴリファイルが元のクラスに含まれていることです。

Location.h

@interface Location : NSManagedObject

@end

#import "Location+CoreDataProperties.h"

これにより、元のクラスでカテゴリで指定されたプロパティを編集できます。

0
mikeho

編集:警告:このプロパティは、クラスのすべてのインスタンスに対して一意の値を持ちます。

これは私にとってはうまくいきましたが、アプリにこのクラスのインスタンスが1つしかないためです。

#import <AVFoundation/AVFoundation.h>

@interface AVAudioPlayer (AstroAVAudioPlayer)

@property (nonatomic) BOOL redPilot;

@end


#import "AVAudioPlayer+AstroAVAudioPlayer.h"

@implementation AVAudioPlayer (AstroAVAudioPlayer)

BOOL _redPilot;

-(void) setRedPilot:(BOOL)redPilot
{
    _redPilot = redPilot;
}

-(BOOL) redPilot
{
    return _redPilot;
}

@end
0
Maxim Chetrusca

これに対する解決策は、フラグを付けたい各オブジェクトに一意のタグを付けることでした。

すべてのラベルにカスタムフォントを追加するためにUILabelカテゴリを作成しましたが、一部では太字にしたいので、これを行いました->

- (void) layoutSubviews {
    [super layoutSubviews];
    [self addCustomFont];   
}

- (void) addCustomFont {
    if (self.tag == 22) {
        [self setFont:[UIFont fontWithName:SEGOE_BOLD size:self.font.pointSize]];
    }else{
        [self setFont:[UIFont fontWithName:SEGOE_LIGHT size:self.font.pointSize]];
    }
}
0
shokaveli