Letezo Class-t 2 felekeppen lehet kiboviteni oroklodes nelkul:
1. Categories (amivel egy letezo Class-hoz lehet method-okat adni):
@interface ClassName (CategoryName)
..
@end
pl:
hederbe (XYPerson+XYPersonExtraMethods.h):
#import “XYPerson.h”
@interface XYPerson (XYPersonExtraMethods)
- (NSString *)lastNameFirstNameString;
@end
implementacio (XYPerson+XYPersonExtraMethods.m):
#import “XYPerson+XYPersonExtraMethods.m;
@implementation XYPerson (XYPersonExtraMethods)
- (NSString *)lastNameFirstNameString {
return [NSString stringWithFormat:@”%@, %@”, self.lastName, self.fistName];
}
@end
Es utana igy lehet meghivni:
#import “XYPerson+XYPersonExtraMethods.h”;
@implementation someObject
- (void)someMethod {
XYPerson *person = [[XYPerson alloc] initWithDefaultValues];
NSLog(@”%@”, [person lastNameFirstNameString]);
}
@end
Vigyazni kell, mert ha 2 kulonbozo helyen is definialva van Category ugyanarra a Class-ra es elofordul ugyanolyan method mindket Category-ban, akkor undefinded, hogy futasi idoben melyik hivodik meg. Felul is lehet irni az eredti Class method-jat, de ha az eredetileg is egy Category-ban volt definialva akkor megint csak undefined, hogy melyik hivodik meg. Erre megoldas a Method Swizzling.
2. Class Extension (amivel egy Class internal impelmentaciojat lehet kiboviteni):
Hasonlit a Category-ra, de csak olyan Class-on lehet alkalmazni aminek megvan a soruce kodja (egy compile soran forditodik le mindketto es az eredeti Class implementaciojaba kell beleirni).
Anonymous Category-nak is hivjak es igy nez ki:
@interface ClassName () {
id _someCustomInstanceVariable; //igy lehet instance valtozot hozzaadni
}
@property NSObject *extraProperty; //A Category-val szemben itt property-ket is lehet definialni
@end
Sokszor private property-k es method-ok letrehozasara hasznaljak: readonly-nak adunk meg valamit az interface-n es readwrite-nak Class Extension-ban.
XYPerson.h:
@interface XYPerson: NSObject
…
@property (readonly) NSString *anyProp;
- (void)assignAnyProp;
@end
XYPerson.m:
@interface XYPerson ()
@property (readwrite) NSString *anyProp; //readwrite elhagyhato, mert az a default
@end
@implementation XYPerson
…
@end
A compiler letrehoz egy settert igy most anyProperty csak belulrol allithato.
-----------------------
Egy letezo Class letezo Method-janak lecserelese. Ugyan Category-val is lehet override-olni meglevo Method-ot, de ha eredetileg is egy Category-ban volt a method akkor undefined, hogy melyik valtozat fut le, raadasul Mehod Swizzling-gel az eredeti method-ot is meg lehet hivni. A megoldas, hogy az uj method-ot mashogy nevezzuk el, majd kicsereljuk oket:
@implementation NSView (MyOverride)
- (void) override_drawRect: (NSRect)r {
[self override_drawrect: r]; //itt valojaban mar a kicserelt eredeti drawRect-et hivjuk
//whatever we want to add to the original method
}
@end
Igy csereljuk meg az uj method-ot az eredetivel:
void MehtodSwizzle(Class c, SEL origSEL, SEL overrideSEL) {
Method origMethod = class_getInstanceMethod(c, origSEL);
Method overrideMethod = class_getInstanceMethod( c, overrideSEL);
//ha a method az eredeti Class superclass-aban letezik azt kulon kell kezelni mivel a class_getInstanceMethod ott is keres. Mivel a class_addMethod nem erinti a superclass-t ezert azzal lehet kiszurni hogy hol volt az origSEL eredetileg
if (class_addMethod(c, origSEL,
method_getImplementation(overrideMethod),
method_getTypEncoding(overrideMethod))) {
//ha az addMethod sikerult akkor az origSEL az origClass superclass-aban volt, de most mar ott van az origClass-ban az overrideMethod implementeaciojaval, mar csak az overrideSEL-t kell hozzaadni az origClass superclassaban levo origSEL implementaciojaval
class_replaceMethod(c, overrideSEL,
method_getImplementation(orgiMethod),
method_getTypeEncoding(origMethod));
}
else {
//ha az addMethod failed akkor az origClass-ban volt definialva az origMethod nem pedig a superclass-aban es ilyenkor siman meg lehet cserelni helyben a 2 method-ot
method_exchangeImplementation(origMethod, overrideMethod);
}
}
Vegul meg biztosnak kell lenni, hogy a MeghodSwizzle meghivodik a progam indulasanal es ezt elintezhetjuk a Category-ban:
+ (void)load {
MethodSwizzle(self, @selector(drawRect:),
@selector(override_drawRect));
}