Настройка новых свойств в категории интерфейса/реализации

Итак, у меня это есть, но это не работает:

@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 - но включение @synthesize в @implementation также вызывает ошибку). Но с методами getter и setter я получаю EXC_BAD_ACCESS и сбой. Есть идеи? Благодаря

Tom

Ответы

Ответ 1

Невозможно добавить элементы и свойства в существующий класс с помощью методов только для категорий.

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

Одним из возможных способов обхода является написать методы "setter/getter-like", в которых используется одиночный символ для сохранения переменных, которые были бы членами.

-(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: Ассоциативные ссылки

Ответ 2

Проверил все ответы и не нашел наиболее распространенного решения:

#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)
        }
    }
}

Ответ 3

На самом деле есть способ, который может быть не идеальным, но действительно работает.
Для его работы вам необходимо создать категорию для класса X и ее можно использовать только в подклассах того же X (например, категория UIView (Background) может использоваться с классом 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

Используя этот метод, вам нужно будет "обновить" свои свойства, но после этого вы сможете выполнять все свои манипуляции внутри своей категории.

Ответ 4

Вы можете внедрить связанный объект во время выполнения.

#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

Ответ 5

EDIT: Warning: это свойство будет иметь уникальное значение для всех экземпляров класса.

Это сработало для меня, но только потому, что у меня был только один экземпляр этого класса в моем приложении.

#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

Ответ 6

Решение, которое я нашел для этого, состояло в том, чтобы просто предоставить каждому объекту, для которого вы хотите пометить уникальный тег.

Я создал категорию 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]];
    }
}

Ответ 7

Кажется, что с Xcode 7 (7.0.1, 7A1001) свойства поддерживаются в категориях. Я заметил, что Xcode генерирует категории для подклассов Core Data.

Например, я получил файлы:

Расположение + 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

Расположение + CoreDataProperties.m

#import "Location+CoreDataProperties.h"

@implementation Location (CoreDataProperties)

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

@end

Итак, похоже, что свойства в категориях могут теперь работать. Я не тестировал нечетные классы данных.

Я заметил, что они включают файл категории обратно в исходный класс:

Location.h

@interface Location : NSManagedObject

@end

#import "Location+CoreDataProperties.h"

Это позволяет исходному классу редактировать свойства, указанные в категории.