2010-11-04 2 views
13

Итак, у меня есть, но это не будет работать:настройка новых свойств в категории интерфейсе/реализации

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

Том

+0

Этот парень «Dave Делонг» опубликовал ответ, что вы должны проверить ... это, наверное, «правильный» способ сделать то, что вы хотите ... :) [вот ссылка ...] (HTTP : //stackoverflow.com/questions/4146183/instance-variables-for-objective-c-categories) –

+1

Ассоциативная ссылка - это решение ... найти хороший учебник здесь http://www.techpaa.com/2012/04/adding -properties-to-categories-and.html – ShivaPrasad

+1

Кроме того, ваш 'isMethodStep' getter является бесконечно рекурсивной функцией. Вот почему вы получаете краху EXC_BAD_ACCESS. 'self.isMethodStep' эквивалентен' [self isMethodStep] '. –

ответ

39

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

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

Одним из возможных способов заключается в писать «/ геттер-сеттер, как» методы, которые использует одноэлементный для сохранения переменных, что бы был членом.

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

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

или - конечно - написать пользовательский класс, который наследует от UILabel


Следует отметить, что в настоящее время связанный объект может быть введен во время выполнения. The Objective C Programming Language: Associative References

+0

"или, конечно же, - написать пользовательский класс, который наследует от UILabel", будет гораздо менее неприятным. :) Плохие новости а? ах ... ну, спасибо. :) –

+0

+1 для отличного ответа –

+0

здесь вы идете :-) –

0

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 
+2

Этот ответ должен быть помечен как неправильный. В приведенной выше реализации выделяется только одно свойство, называемое _redPilot для всех экземпляров AVAudioPlayer. Другими словами, если у вас есть три экземпляра AVAudioPlayer, тогда avAudioPlayer1.redPilot == avAudioPlayer2.redPilot == avAudioPlayer3.redPilot всегда. – noobular

+1

@nobular, Вы правы, сэр. Действительно, в моем случае у меня был только один экземпляр AVAudioPlayer, поэтому я не очень заботился об этом. Я все равно ответил на это, потому что думал, что это может помочь кому-то, например, кому-то вроде меня. Я бы отредактировал ответ, чтобы он предупреждал об упомянутой выше проблеме. –

+0

Вот техника, которую я использовал в прошлом для решения проблемы отсутствия свойств по категориям: http://www.techpaa.com/2012/04/adding-properties-to-categories-and.html – noobular

0

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

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

Существует на самом деле путь, который не может быть идеальным , но работает.
Для того, чтобы работать, вам нужно будет создать категорию для класса 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 

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

0

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

К примеру, у меня есть файлы:

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

Так выглядит свойства в категориях может работать сейчас. Я не тестировал на объектах Core Data.

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

Location.h

@interface Location : NSManagedObject 

@end 

#import "Location+CoreDataProperties.h" 

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

3

Проверено все ответы и не нашли наиболее общее решение:

#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 
+0

Идеальное решение! Спасибо! –

0

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

#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 
Смежные вопросы